如何实现从物联网平台控制设备属性值 您所在的位置:网站首页 阿里云物联网 控制设备的软件有哪些 如何实现从物联网平台控制设备属性值

如何实现从物联网平台控制设备属性值

2024-07-03 06:19| 来源: 网络整理| 查看: 265

背景信息

灯泡设备接入物联网平台后,若需从物联网平台控制灯泡工作状态(1:打开;0:关闭),需要灯泡一直保持连网在线。实际情况下,灯泡可能无法一直在线。

您可在物联网平台设置设备期望属性值,使其存储在物联网平台云端。设备在线后,可读取物联网平台存储的期望属性值,来更新自身属性值。然后,设备会将更新后的属性值上报至物联网平台,在物联网平台的设备运行状态中显示。

创建产品和设备登录物联网平台控制台。

实例概览页签的全部环境下,找到对应的实例,单击实例卡片。

在左侧导航栏,选择设备管理 > 产品,单击创建产品,创建一个产品:灯泡。创建产品产品创建成功后,单击前往定义物模型,为产品添加物模型并发布,请参见单个添加物模型。如图所示,本示例添加属性工作状态(LightStatus)。物模型在左侧导航栏,选择设备管理 > 设备,单击添加设备,在灯泡产品下添加设备:Lamp。添加设备设备添加成功后,获取设备证书信息(ProductKey、DeviceName和DeviceSecret)。

您可在设备列表,单击设备Lamp对应的查看进入设备详情页面,查看运行状态,设备属性值和期望属性值都为空。此时期望属性值版本为0。

运行状态初始在云端设置和查询期望属性值

您可在通过调用物联网平台云端API,设置和获取设备最新期望属性值。

具体操作,请参见云端API。本文以Java SDK(云端)为例。

调用SetDeviceDesiredProperty,设置期望属性值。 DefaultProfile profile = DefaultProfile.getProfile( "", // 地域ID "", //阿里云账号的AccessKey ID ""); 阿里云账号AccessKey Secret IAcsClient client = new DefaultAcsClient(profile); // 创建API请求并设置参数 SetDeviceDesiredPropertyRequest request = new SetDeviceDesiredPropertyRequest(); request.setIotInstanceId("iot-060***"); request.setDeviceName("Lamp"); request.setProductKey("g4r***"); // 待设置的属性identifier与期望属性值 request.setItems("{\"LightStatus\": 1}"); request.setVersions("{\"LightStatus\": 0}"); // 发起请求并处理应答或异常 try { SetDeviceDesiredPropertyResponse response = client.getAcsResponse(request); System.out.println(new Gson().toJson(response)); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { System.out.println("ErrCode:" + e.getErrCode()); System.out.println("ErrMsg:" + e.getErrMsg()); System.out.println("RequestId:" + e.getRequestId()); }调用QueryDeviceDesiredProperty,查看设备的期望属性值。 DefaultProfile profile = DefaultProfile.getProfile( "", // 地域ID "", /阿里云账号的AccessKey ID ""); 阿里云账号Access Key Secret IAcsClient client = new DefaultAcsClient(profile); // 创建API请求并设置参数 QueryDeviceDesiredPropertyRequest request = new QueryDeviceDesiredPropertyRequest(); request.setIotInstanceId("iot-06****"); request.setProductKey("g4r****"); request.setDeviceName("Lamp"); // 待查询的属性identifier列表。如不指定则查询所有属性(只读属性除外)的期望属性值。 List identifierList = new ArrayList(); identifierList.add("LightStatus"); request.setIdentifiers(identifierList); // 发起请求并处理应答或异常 try { QueryDeviceDesiredPropertyResponse response = client.getAcsResponse(request); System.out.println(new Gson().toJson(response)); } catch (ServerException e) { e.printStackTrace(); } catch (ClientException e) { System.out.println("ErrCode:" + e.getErrCode()); System.out.println("ErrMsg:" + e.getErrMsg()); System.out.println("RequestId:" + e.getRequestId()); }

有关如何设置代码中参数,请参见Java SDK使用说明。

在物联网平台云端设置设备期望属性值后,设备运行状态显示该值。

运行状态期望设备端开发

设备获取期望属性值,有两种场景:

灯泡重新上线时,主动获取物联网平台云端缓存的期望属性值。灯泡正处于上线状态,实时接收物联网平台云端推送的期望属性值。

设备端开发更多信息,请参见使用设备端SDK接入。

本文以Java SDK为例,提供了完整的设备端Demo示例,请参见下文附录:设备端Demo代码。

填入设备证书、地域和MQTT接入地址的信息。 /** * 设备证书信息 */ private static String productKey = "******"; private static String deviceName = "********"; private static String deviceSecret = "**************"; /** * MQTT连接信息 */ private static String regionId = "******"; ...... /** * 设置 Mqtt 初始化参数 */ config.channelHost = deviceInfo.productKey + ".iot-as-mqtt." + region + ".aliyuncs.com:1883";说明 设备证书信息,请参见本文上方创建产品和设备。regionId 为您的服务所在地域对应的Region ID。请在物联网平台控制台左上角,查看您服务所在的地域。Region ID表达方法,请参见支持的地域。channelHost 为MQTT接入地址。获取方法,请参见查看和配置实例终端节点信息(Endpoint)。添加以下方法,用于变更实际灯泡的属性,并在属性变更后,主动将信息上报到最新属性值中。 /** * 真实设备处理属性变更时,在以下两个场下会被调用: * 场景1. 设备联网后主动获取最新的属性期望值(由设备发起,拉模式) * 场景2. 设备在线时接收到云端property.set推送的属性期望值(由云端发起,推模式) * @param identifier 属性标识符 * @param value 期望属性值 * @param needReport 是否通过property.post发送状态上报。 * 上面场景2的处理函数中已集成属性上报能力,会将needReport设置为false * @return */ private boolean handlePropertySet(String identifier, ValueWrapper value, boolean needReport) { ALog.d(TAG, "真实设备处理属性变更 = [" + identifier + "], value = [" + value + "]"); // 用户根据实际情况判性是否设置成功,这里测试直接返回成功 boolean success = true; if (needReport) { reportProperty(identifier, value); } return success; } private void reportProperty(String identifier, ValueWrapper value){ if (StringUtils.isEmptyString(identifier) || value == null) { return; } ALog.d(TAG, "上报属性identity=" + identifier); Map reportData = new HashMap(); reportData.put(identifier, value); LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() { public void onSuccess(String s, Object o) { // 属性上报成功 ALog.d(TAG, "上报成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]"); } public void onError(String s, AError aError) { // 属性上报失败 ALog.d(TAG, "上报失败onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]"); } }); }灯泡在线时,如果物联网平台设置了灯泡的期望属性值,该值将被推送到设备端。灯泡处理消息,改变属性状态。

如下代码中,将调用connectNotifyListener处理消息,相关Alink协议说明,请参见设备上报属性。

收到异步下行的数据后,mCommonHandler被调用,进而调用handlePropertySet更新设备的物理属性。

/** * 注册服务调用(以及属性设置)的响应函数。 * 云端调用设备的某项服务的时候,设备端需要响应该服务并回复。 */ public void connectNotifyListener() { List serviceList = LinkKit.getInstance().getDeviceThing().getServices(); for (int i = 0; serviceList != null && i < serviceList.size(); i++) { Service service = serviceList.get(i); LinkKit.getInstance().getDeviceThing().setServiceHandler(service.getIdentifier(), mCommonHandler); } } private ITResRequestHandler mCommonHandler = new ITResRequestHandler() { public void onProcess(String serviceIdentifier, Object result, ITResResponseCallback itResResponseCallback) { ALog.d(TAG, "onProcess() called with: s = [" + serviceIdentifier + "]," + " o = [" + result + "], itResResponseCallback = [" + itResResponseCallback + "]"); ALog.d(TAG, "收到云端异步服务调用 " + serviceIdentifier); try { if (SERVICE_SET.equals(serviceIdentifier)) { Map data = (Map)((InputParams)result).getData(); ALog.d(TAG, "收到异步下行数据 " + data); // 设置真实设备的属性,然后上报设置完成的属性值 boolean isSetPropertySuccess = handlePropertySet("LightStatus", data.get("LightStatus"), false); if (isSetPropertySuccess) { if (result instanceof InputParams) { // 响应云端,接收数据成功 itResResponseCallback.onComplete(serviceIdentifier, null, null); } else { itResResponseCallback.onComplete(serviceIdentifier, null, null); } } else { AError error = new AError(); error.setCode(100); error.setMsg("setPropertyFailed."); itResResponseCallback.onComplete(serviceIdentifier, new ErrorInfo(error), null); } } else if (SERVICE_GET.equals(serviceIdentifier)) { } else { // 根据不同的服务做不同的处理,跟具体的服务有关系 ALog.d(TAG, "根据真实的服务返回服务的值,请参照set示例"); OutputParams outputParams = new OutputParams(); // outputParams.put("op", new ValueWrapper.IntValueWrapper(20)); itResResponseCallback.onComplete(serviceIdentifier, null, outputParams); } } catch (Exception e) { e.printStackTrace(); ALog.d(TAG, "云端返回数据格式异常"); } } public void onSuccess(Object o, OutputParams outputParams) { ALog.d(TAG, "onSuccess() called with: o = [" + o + "], outputParams = [" + outputParams + "]"); ALog.d(TAG, "注册服务成功"); } public void onFail(Object o, ErrorInfo errorInfo) { ALog.d(TAG, "onFail() called with: o = [" + o + "], errorInfo = [" + errorInfo + "]"); ALog.d(TAG, "注册服务失败"); } };灯泡离线后,如果物联网平台云端设置了灯的期望属性值,该值将被存储在云端。

灯泡上线后,会主动获取期望属性值,然后调用handlePropertySet更新实际设备的属性。

LinkKit.getInstance().init(params, new ILinkKitConnectListener() { public void onError(AError aError) { ALog.e(TAG, "Init Error error=" + aError); } public void onInitDone(InitResult initResult) { ALog.i(TAG, "onInitDone result=" + initResult); connectNotifyListener(); // 获取云端最新期望属性值 getDesiredProperty(deviceInfo, Arrays.asList("LightStatus"), new IConnectSendListener() { public void onResponse(ARequest aRequest, AResponse aResponse) { if(aRequest instanceof MqttPublishRequest && aResponse.data != null) { JSONObject jsonObject = JSONObject.parseObject(aResponse.data.toString()); ALog.i(TAG, "onResponse result=" + jsonObject); JSONObject dataObj = jsonObject.getJSONObject("data"); if (dataObj != null) { if (dataObj.getJSONObject("LightStatus") == null) { // 未设置期望值 } else { Integer value = dataObj.getJSONObject("LightStatus").getInteger("value"); handlePropertySet("LightStatus", new ValueWrapper.IntValueWrapper(value), true); } } } } public void onFailure(ARequest aRequest, AError aError) { ALog.d(TAG, "onFailure() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]"); } }); } }); private void getDesiredProperty(BaseInfo info, List properties, IConnectSendListener listener) { ALog.d(TAG, "getDesiredProperty() called with: info = [" + info + "], listener = [" + listener + "]"); if(info != null && !StringUtils.isEmptyString(info.productKey) && !StringUtils.isEmptyString(info.deviceName)) { MqttPublishRequest request = new MqttPublishRequest(); request.topic = DESIRED_PROPERTY_GET.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName); request.replyTopic = DESIRED_PROPERTY_GET_REPLY.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName); request.isRPC = true; RequestModel model = new RequestModel(); model.id = String.valueOf(IDGeneraterUtils.getId()); model.method = METHOD_GET_DESIRED_PROPERTY; model.params = properties; model.version = "1.0"; request.payloadObj = model.toString(); ALog.d(TAG, "getDesiredProperty: payloadObj=" + request.payloadObj); ConnectSDK.getInstance().send(request, listener); } else { ALog.w(TAG, "getDesiredProperty failed, baseInfo Empty."); if(listener != null) { AError error = new AError(); error.setMsg("BaseInfoEmpty."); listener.onFailure(null, error); } } }验证结果

根据以下场景运行代码,验证灯泡在线、离线状态,可在物联网平台云端通过设置期望属性值,成功更改设备属性值。

设备在线时,云端修改灯泡开关状态,灯泡实时响应状态变化。在线更新设备离线后,如果云端修改灯泡开关状态,云端期望属性值与设备的最新属性值不一致。离线更新设备重新连网上线后,设备主动拉取期望属性值,设备的最新属性值实现与云端期望属性值的同步。重连更新附录:设备端Demo代码package com.aliyun.alink.devicesdk.demo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.aliyun.alink.apiclient.utils.StringUtils; import com.aliyun.alink.dm.api.BaseInfo; import com.aliyun.alink.dm.api.DeviceInfo; import com.aliyun.alink.dm.api.InitResult; import com.aliyun.alink.dm.model.RequestModel; import com.aliyun.alink.dm.utils.IDGeneraterUtils; import com.aliyun.alink.linkkit.api.ILinkKitConnectListener; import com.aliyun.alink.linkkit.api.IoTMqttClientConfig; import com.aliyun.alink.linkkit.api.LinkKit; import com.aliyun.alink.linkkit.api.LinkKitInitParams; import com.aliyun.alink.linksdk.cmp.api.ConnectSDK; import com.aliyun.alink.linksdk.cmp.connect.channel.MqttPublishRequest; import com.aliyun.alink.linksdk.cmp.core.base.ARequest; import com.aliyun.alink.linksdk.cmp.core.base.AResponse; import com.aliyun.alink.linksdk.cmp.core.listener.IConnectSendListener; import com.aliyun.alink.linksdk.tmp.api.InputParams; import com.aliyun.alink.linksdk.tmp.api.OutputParams; import com.aliyun.alink.linksdk.tmp.device.payload.ValueWrapper; import com.aliyun.alink.linksdk.tmp.devicemodel.Service; import com.aliyun.alink.linksdk.tmp.listener.IPublishResourceListener; import com.aliyun.alink.linksdk.tmp.listener.ITResRequestHandler; import com.aliyun.alink.linksdk.tmp.listener.ITResResponseCallback; import com.aliyun.alink.linksdk.tmp.utils.ErrorInfo; import com.aliyun.alink.linksdk.tools.AError; import com.aliyun.alink.linksdk.tools.ALog; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class LampDemo { private static final String TAG = "LampDemo"; private final static String SERVICE_SET = "set"; private final static String SERVICE_GET = "get"; public static String DESIRED_PROPERTY_GET = "/sys/${productKey}/${deviceName}/thing/property/desired/get"; public static String DESIRED_PROPERTY_GET_REPLY = "/sys/${productKey}/${deviceName}/thing/property/desired/get_reply"; public static String METHOD_GET_DESIRED_PROPERTY = "thing.property.desired.get"; public static void main(String[] args) { /** * 设备证书信息 */ String productKey = "****"; String deviceName = "Lamp"; String deviceSecret = "****"; /** * mqtt连接信息 */ String regionId = "cn-shanghai"; LampDemo manager = new LampDemo(); DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.productKey = productKey; deviceInfo.deviceName = deviceName; deviceInfo.deviceSecret = deviceSecret; manager.init(deviceInfo, regionId); } public void init(final DeviceInfo deviceInfo, String region) { LinkKitInitParams params = new LinkKitInitParams(); /** * 设置 Mqtt 初始化参数 */ IoTMqttClientConfig config = new IoTMqttClientConfig(); config.productKey = deviceInfo.productKey; config.deviceName = deviceInfo.deviceName; config.deviceSecret = deviceInfo.deviceSecret; config.channelHost = deviceInfo.productKey + ".iot-as-mqtt." + region + ".aliyuncs.com:1883"; /** * 是否接受离线消息 * 对应 mqtt 的 cleanSession 字段 */ config.receiveOfflineMsg = false; params.mqttClientConfig = config; /** * 设置初始化,传入设备证书信息 */ params.deviceInfo = deviceInfo; LinkKit.getInstance().init(params, new ILinkKitConnectListener() { public void onError(AError aError) { ALog.e(TAG, "Init Error error=" + aError); } public void onInitDone(InitResult initResult) { ALog.i(TAG, "onInitDone result=" + initResult); connectNotifyListener(); // 获取云端最新期望属性值 getDesiredProperty(deviceInfo, Arrays.asList("LightStatus"), new IConnectSendListener() { public void onResponse(ARequest aRequest, AResponse aResponse) { if(aRequest instanceof MqttPublishRequest && aResponse.data != null) { JSONObject jsonObject = JSONObject.parseObject(aResponse.data.toString()); ALog.i(TAG, "onResponse result=" + jsonObject); JSONObject dataObj = jsonObject.getJSONObject("data"); if (dataObj != null) { if (dataObj.getJSONObject("LightStatus") == null) { // 未设置期望值 } else { Integer value = dataObj.getJSONObject("LightStatus").getInteger("value"); handlePropertySet("LightStatus", new ValueWrapper.IntValueWrapper(value), true); } } } } public void onFailure(ARequest aRequest, AError aError) { ALog.d(TAG, "onFailure() called with: aRequest = [" + aRequest + "], aError = [" + aError + "]"); } }); } }); } /** * 真实设备处理属性变更,两个场景下会被调用: * 场景1. 设备联网后主动获取最新的属性期望值(由设备发起,拉模式) * 场景2. 设备在线时接收到云端property.set推送(由云端发起,推模式) * @param identifier 属性标识符 * @param value 期望属性值 * @param needReport 是否发送property.post状态上报。 * 上面场景2的处理函数中已集成属性上报能力,会将needReport设置为false * @return */ private boolean handlePropertySet(String identifier, ValueWrapper value, boolean needReport) { ALog.d(TAG, "真实设备处理属性变更 = [" + identifier + "], value = [" + value + "]"); // 用户根据实际情况判断属性是否设置成功,这里测试直接返回成功 boolean success = true; if (needReport) { reportProperty(identifier, value); } return success; } private void reportProperty(String identifier, ValueWrapper value){ if (StringUtils.isEmptyString(identifier) || value == null) { return; } ALog.d(TAG, "上报属性identity=" + identifier); Map reportData = new HashMap(); reportData.put(identifier, value); LinkKit.getInstance().getDeviceThing().thingPropertyPost(reportData, new IPublishResourceListener() { public void onSuccess(String s, Object o) { // 属性上报成功 ALog.d(TAG, "上报成功 onSuccess() called with: s = [" + s + "], o = [" + o + "]"); } public void onError(String s, AError aError) { // 属性上报失败 ALog.d(TAG, "上报失败onError() called with: s = [" + s + "], aError = [" + JSON.toJSONString(aError) + "]"); } }); } /** * 注册服务调用(以及属性设置)的响应函数。 * 云端调用设备的某项服务的时候,设备端需要响应该服务并回复。 */ public void connectNotifyListener() { List serviceList = LinkKit.getInstance().getDeviceThing().getServices(); for (int i = 0; serviceList != null && i < serviceList.size(); i++) { Service service = serviceList.get(i); LinkKit.getInstance().getDeviceThing().setServiceHandler(service.getIdentifier(), mCommonHandler); } } private ITResRequestHandler mCommonHandler = new ITResRequestHandler() { public void onProcess(String serviceIdentifier, Object result, ITResResponseCallback itResResponseCallback) { ALog.d(TAG, "onProcess() called with: s = [" + serviceIdentifier + "]," + " o = [" + result + "], itResResponseCallback = [" + itResResponseCallback + "]"); ALog.d(TAG, "收到云端异步服务调用 " + serviceIdentifier); try { if (SERVICE_SET.equals(serviceIdentifier)) { Map data = (Map)((InputParams)result).getData(); ALog.d(TAG, "收到异步下行数据 " + data); // 设置真实设备的属性,然后上报设置完成的属性值 boolean isSetPropertySuccess = handlePropertySet("LightStatus", data.get("LightStatus"), false); if (isSetPropertySuccess) { if (result instanceof InputParams) { // 响应云端,接收数据成功 itResResponseCallback.onComplete(serviceIdentifier, null, null); } else { itResResponseCallback.onComplete(serviceIdentifier, null, null); } } else { AError error = new AError(); error.setCode(100); error.setMsg("setPropertyFailed."); itResResponseCallback.onComplete(serviceIdentifier, new ErrorInfo(error), null); } } else if (SERVICE_GET.equals(serviceIdentifier)) { } else { // 根据不同的服务做不同的处理,跟具体的服务有关系 ALog.d(TAG, "用户根据真实的服务返回服务的值,请参照set示例"); OutputParams outputParams = new OutputParams(); // outputParams.put("op", new ValueWrapper.IntValueWrapper(20)); itResResponseCallback.onComplete(serviceIdentifier, null, outputParams); } } catch (Exception e) { e.printStackTrace(); ALog.d(TAG, "云端返回数据格式异常"); } } public void onSuccess(Object o, OutputParams outputParams) { ALog.d(TAG, "onSuccess() called with: o = [" + o + "], outputParams = [" + outputParams + "]"); ALog.d(TAG, "注册服务成功"); } public void onFail(Object o, ErrorInfo errorInfo) { ALog.d(TAG, "onFail() called with: o = [" + o + "], errorInfo = [" + errorInfo + "]"); ALog.d(TAG, "注册服务失败"); } }; private void getDesiredProperty(BaseInfo info, List properties, IConnectSendListener listener) { ALog.d(TAG, "getDesiredProperty() called with: info = [" + info + "], listener = [" + listener + "]"); if(info != null && !StringUtils.isEmptyString(info.productKey) && !StringUtils.isEmptyString(info.deviceName)) { MqttPublishRequest request = new MqttPublishRequest(); request.topic = DESIRED_PROPERTY_GET.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName); request.replyTopic = DESIRED_PROPERTY_GET_REPLY.replace("{productKey}", info.productKey).replace("{deviceName}", info.deviceName); request.isRPC = true; RequestModel model = new RequestModel(); model.id = String.valueOf(IDGeneraterUtils.getId()); model.method = METHOD_GET_DESIRED_PROPERTY; model.params = properties; model.version = "1.0"; request.payloadObj = model.toString(); ALog.d(TAG, "getDesiredProperty: payloadObj=" + request.payloadObj); ConnectSDK.getInstance().send(request, listener); } else { ALog.w(TAG, "getDesiredProperty failed, baseInfo Empty."); if(listener != null) { AError error = new AError(); error.setMsg("BaseInfoEmpty."); listener.onFailure(null, error); } } } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有